/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.transaction.interceptor;

import java.io.Serializable;
import java.lang.reflect.Method;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.lang.Nullable;
import org.springframework.transaction.TransactionManager;
import org.springframework.util.ObjectUtils;

/**
 * Abstract class that implements a Pointcut that matches if the underlying
 * {@link TransactionAttributeSource} has an attribute for a given method.
 *
 * @author Juergen Hoeller
 * @since 2.5.5
 */
/*
1. 总结
TransactionAttributeSourcePointcut 是 Spring 事务框架中的一个抽象类，用于实现基于 TransactionAttributeSource 的切点匹配逻辑。
它继承自 StaticMethodMatcherPointcut，在方法调用前静态判断是否需要事务处理。
主要用于 BeanFactoryTransactionAttributeSourceAdvisor 中，作为判断方法是否需要事务的切点。
2. 内部成员说明
字段
无显式字段定义。
方法
matches(Method method, Class<?> targetClass): 判断给定方法和目标类是否匹配切点。如果 TransactionAttributeSource 返回非空事务属性，则匹配。
equals(Object other): 实现对象相等性比较，基于 TransactionAttributeSource 的相等性。
hashCode(): 返回对象的哈希码，使用类的哈希码。
toString(): 返回对象的字符串表示，包含类名和 TransactionAttributeSource。
getTransactionAttributeSource(): 抽象方法，由子类实现，用于获取底层的 TransactionAttributeSource。
TransactionAttributeSourceClassFilter: 内部类，实现 ClassFilter 接口，用于过滤不需要检查的类。
3. 类关系结构
Pointcut (interface)
└── StaticMethodMatcherPointcut (abstract class)
    └── TransactionAttributeSourcePointcut (abstract class)
        └── BeanFactoryTransactionAttributeSourceAdvisor$TransactionAttributeSourcePointcut (class)

相关类和接口关系说明
	Pointcut: 最顶层接口，定义了切点的基本契约。
	StaticMethodMatcherPointcut: 抽象基类，实现了 Pointcut 接口，提供了静态方法匹配的实现。
	TransactionAttributeSource: 提供事务属性检索功能的接口，TransactionAttributeSourcePointcut 通过它来判断方法是否需要事务处理。
	BeanFactoryTransactionAttributeSourceAdvisor: 使用 TransactionAttributeSourcePointcut 作为其内部切点，实现事务增强。
4. 使用场景
	在 Spring 事务管理中，作为 BeanFactoryTransactionAttributeSourceAdvisor 的切点。
	用于判断方法是否需要事务处理，基于 TransactionAttributeSource 的配置。
	在 AOP 代理中确定哪些方法需要应用事务拦截器。
5. 实际代码应用示例
// 在 BeanFactoryTransactionAttributeSourceAdvisor 中的使用方式
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

    @Nullable
    private TransactionAttributeSource transactionAttributeSource;

    private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
        @Override
        @Nullable
        protected TransactionAttributeSource getTransactionAttributeSource() {
            return transactionAttributeSource;
        }
    };

    public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) {
        this.transactionAttributeSource = transactionAttributeSource;
    }

    @Override
    public Pointcut getPointcut() {
        return this.pointcut;
    }
}


 */
@SuppressWarnings("serial")
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {

	protected TransactionAttributeSourcePointcut() {
		setClassFilter(new TransactionAttributeSourceClassFilter());
	}

	/*
	matches 方法的作用是判断给定的方法和目标类是否需要应用事务处理。
	获取事务属性源
		通过 getTransactionAttributeSource() 获取底层的 TransactionAttributeSource 对象
	判断是否需要事务
		如果事务属性源为 null，则返回 true（表示需要事务）
		否则调用 TransactionAttributeSource.getTransactionAttribute() 方法获取方法的事务属性
		如果返回的事务属性不为 null，则表示该方法需要事务处理，返回 true
	 */
	@Override
	public boolean matches(Method method, Class<?> targetClass) {
		//AnnotationTransactionAttributeSource (class)	最常用的实现，基于 @Transactional 注解获取事务属性。
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

	@Override
	public boolean equals(@Nullable Object other) {
		if (this == other) {
			return true;
		}
		if (!(other instanceof TransactionAttributeSourcePointcut)) {
			return false;
		}
		TransactionAttributeSourcePointcut otherPc = (TransactionAttributeSourcePointcut) other;
		return ObjectUtils.nullSafeEquals(getTransactionAttributeSource(), otherPc.getTransactionAttributeSource());
	}

	@Override
	public int hashCode() {
		return TransactionAttributeSourcePointcut.class.hashCode();
	}

	@Override
	public String toString() {
		return getClass().getName() + ": " + getTransactionAttributeSource();
	}


	/**
	 * Obtain the underlying TransactionAttributeSource (may be {@code null}).
	 * To be implemented by subclasses.
	 */
	@Nullable
	protected abstract TransactionAttributeSource getTransactionAttributeSource();


	/**
	 * {@link ClassFilter} that delegates to {@link TransactionAttributeSource#isCandidateClass}
	 * for filtering classes whose methods are not worth searching to begin with.
	 */
	/*
	TransactionAttributeSourceClassFilter 是 TransactionAttributeSourcePointcut 的内部类，
	实现了 ClassFilter 接口，用于过滤掉不需要进行事务属性检查的类。
		排除特定类型
			排除实现了 TransactionalProxy 的代理类
			排除实现了 TransactionManager 的事务管理器类
			排除实现了 PersistenceExceptionTranslator 的持久化异常转换器类
		委托候选类检查
			当不属于上述排除类型时，委托给 TransactionAttributeSource 的 isCandidateClass() 方法进一步判断

	 */
	private class TransactionAttributeSourceClassFilter implements ClassFilter {

		@Override
		public boolean matches(Class<?> clazz) {
			if (TransactionalProxy.class.isAssignableFrom(clazz) ||
					TransactionManager.class.isAssignableFrom(clazz) ||
					PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
				return false;
			}
			TransactionAttributeSource tas = getTransactionAttributeSource();
			return (tas == null || tas.isCandidateClass(clazz));
		}
	}

}
